package com.googlecode.erebos.server;


import com.googlecode.erebos.ErebosObject;
import com.googlecode.erebos.Location;
import com.sun.sgs.app.AppContext;
import com.sun.sgs.app.ManagedReference;

import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;

/**
 * The MIT License
 * <p/>
 * Copyright (c) 2009 Malachi de AElfweald (malachid@gmail.com)
 * <p/>
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * <p/>
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * <p/>
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */


public class ErebosObjectImpl
implements ErebosObject, Serializable
{
    /** The version of the serialized form of this class. */
    private static final long serialVersionUID = 1L;

    /** The message encoding. */
    public static final String MESSAGE_CHARSET = "UTF-8";

    private String name;
    private String description;
    private double health;
    private ManagedReference<LocationImpl> location;
    private ManagedReference<SizeImpl> size;

    public ErebosObjectImpl()
    {
        name = this.getClass().getSimpleName();
        description = String.format("a %s", name);
        health = 100.0;
    }

    public void bind(BindingPrefix prefix)
    {
        AppContext.getDataManager().setBinding(prefix.getName(name), this);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        AppContext.getDataManager().markForUpdate(this);
        this.name = name;
    }

    public double getHealth() {
        return health;
    }

    /**
     * If a standalone object, return the location of the object.
     * <p/>
     * In order to reduce processing requirements, if the object is contained in another
     * object, returns null to signify that its' location is dependant on another object.
     *
     * @return location or null
     */
    public LocationImpl getLocation() {
        if(location == null)
            return null;

        return location.get();
    }

    public SizeImpl getSize()
    {
        if(size == null)
            return null;

        return size.get();
    }

    /**
     * If a standalone object, set the location of the object.
     * <p/>
     * In order to reduce processing requirements, if the object is contained in another
     * object, set null to signify that its' location is dependant on another object.
     *
     * @param location or null
     */
    public void setLocation(LocationImpl location)
    {
        AppContext.getDataManager().markForUpdate(this);
        if(location == null)
            this.location = null;
        else
            this.location = AppContext.getDataManager().createReference(location);
    }

    public void setSize(SizeImpl size)
    {
        AppContext.getDataManager().markForUpdate(this);
        if(size == null)
            this.size = null;
        else
            this.size = AppContext.getDataManager().createReference(size);
    }

    public void setHealth(double health) {
        AppContext.getDataManager().markForUpdate(this);
        this.health = health;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        AppContext.getDataManager().markForUpdate(this);
        this.description = description;
    }

    /**
     * Encodes a {@code String} into a {@link ByteBuffer}.
     *
     * @param s the string to encode
     * @return the {@code ByteBuffer} which encodes the given string
     */
    protected static ByteBuffer encodeString(String s) {
        try {
            return ByteBuffer.wrap(s.getBytes(MESSAGE_CHARSET));
        } catch (UnsupportedEncodingException e) {
            throw new Error("Required character set " + MESSAGE_CHARSET +
                " not found", e);
        }
    }

    /**
     * Decodes a message into a {@code String}.
     *
     * @param message the message to decode
     * @return the decoded string
     */
    protected static String decodeString(ByteBuffer message) {
        try {
            byte[] bytes = new byte[message.remaining()];
            message.get(bytes);
            return new String(bytes, MESSAGE_CHARSET);
        } catch (UnsupportedEncodingException e) {
            throw new Error("Required character set " + MESSAGE_CHARSET +
                " not found", e);
        }
    }
}
